﻿/// <reference path="../../cannon/cannon.d.ts" />
/// <reference path="../../lib/egret3d.d.ts" />

class Basic
{
    _canvasEgret: egret3d.Egret3DCanvas;
    _view3D: egret3d.View3D;
    _cameraCtrl: egret3d.LookAtController;

    N: number = 10;
    boxMeshes: egret3d.Mesh[] = [];
    boxes: CANNON.Body[] = [];

    start()
    {
        this.initCannon();

        this._canvasEgret = new egret3d.Egret3DCanvas();
        this._canvasEgret.x = 0;
        this._canvasEgret.y = 0;
        this._canvasEgret.width = window.innerWidth;
        this._canvasEgret.height = window.innerHeight;
        this._canvasEgret.start();

        var lightGroup = new egret3d.LightGroup();
        var light = new egret3d.DirectLight(new egret3d.Vector3D(0, -1, 1));
        light.diffuse = 0xffffff;
        light.intensity = 1;
        lightGroup.addLight(light);

        this._view3D = new egret3d.View3D(0, 0, window.innerWidth, window.innerHeight);
        this._view3D.camera3D.lookAt(new egret3d.Vector3D(0, 24, -40), new egret3d.Vector3D(0, 0, 0));
        this._view3D.backColor = 0xff333333;
        this._canvasEgret.addView3D(this._view3D);

        var plane = new egret3d.Mesh(new egret3d.PlaneGeometry(200, 200), new egret3d.ColorMaterial());
        plane.material.diffuseColor = 0xaaaaaa;
        plane.material.acceptShadow = true;
        plane.material.castShadow = true;
        plane.material.lightGroup = lightGroup;
        this._view3D.addChild3D(plane);

        // 添加方块
        var halfExtents = new CANNON.Vec3(1, 1, 1);
        var boxShape = new CANNON.Box(halfExtents);
        var boxGeometry = new egret3d.CubeGeometry(halfExtents.x * 2, halfExtents.y * 2, halfExtents.z * 2);
        for (var i = 0; i < this.N; i++)
        {
            var x = (Math.random() - 0.5) * 20;
            var y = 1 + Math.random() * 20;
            var z = (Math.random() - 0.5) * 20;
            var boxBody = new CANNON.Body({ mass: 10 });
            boxBody.addShape(boxShape);
            var boxMesh = new egret3d.Mesh(boxGeometry, new egret3d.ColorMaterial());
            //boxMesh.material.acceptShadow = true;
            boxMesh.material.castShadow = true;
            boxMesh.material.lightGroup = lightGroup;
            this.world.addBody(boxBody);
            this._view3D.addChild3D(boxMesh);
            boxBody.position.set(x, y, z);
            boxMesh.position = new egret3d.Vector3D(x, y, z);
            this.boxes.push(boxBody);
            this.boxMeshes.push(boxMesh);
        }

        // 添加链条
        var size = 0.5;
        var he = new CANNON.Vec3(size, size, size * 0.1);
        var boxShape = new CANNON.Box(he);
        var mass = 0;
        var space = 0.1 * size;
        var N = 5;
        var last: CANNON.Body;
        var boxGeometry = new egret3d.CubeGeometry(he.x * 2, he.y * 2, he.z * 2);
        for (var i = 0; i < N; i++)
        {
            var boxbody = new CANNON.Body({ mass: mass });
            boxbody.addShape(boxShape);
            var boxMesh = new egret3d.Mesh(boxGeometry, new egret3d.ColorMaterial());
            //boxMesh.material.acceptShadow = true;
            boxMesh.material.castShadow = true;
            boxMesh.material.lightGroup = lightGroup;
            boxMesh.position = new egret3d.Vector3D(5, (N - i) * (size * 2 + 2 * space) + size * 2 + space, 0);
            boxbody.position.set(5, (N - i) * (size * 2 + 2 * space) + size * 2 + space, 0);
            //boxbody.position.set(0, 10, 0);
            boxbody.linearDamping = 0.01;
            boxbody.angularDamping = 0.01;
            this.world.addBody(boxbody);
            this._view3D.addChild3D(boxMesh);
            this.boxes.push(boxbody);
            this.boxMeshes.push(boxMesh);

            if (i != 0)
            {
                // 将当前方块与上一个方块相连
                var c1 = new CANNON.PointToPointConstraint(boxbody, new CANNON.Vec3(-size, size + space, 0), last, new CANNON.Vec3(-size, -size - space, 0));
                var c2 = new CANNON.PointToPointConstraint(boxbody, new CANNON.Vec3(size, size + space, 0), last, new CANNON.Vec3(size, -size - space, 0));
                this.world.addConstraint(c1);
                this.world.addConstraint(c2);
            }
            else
            {
                mass = 0.5;
            }
            last = boxbody;
        }

        this.sphereMesh = new egret3d.Mesh(new egret3d.SphereGeometry(1.5), new egret3d.ColorMaterial());
        this.sphereMesh.material.castShadow = true;
        this.sphereMesh.material.lightGroup = lightGroup;
        this._view3D.addChild3D(this.sphereMesh);

        //this._cameraCtrl = new egret3d.LookAtController(this._view3D.camera3D, this.sphereMesh);
        //this._cameraCtrl.distance = 40;
        //this._cameraCtrl.rotationX = 30;

        this._canvasEgret.addEventListener(egret3d.Event3D.ENTER_FRAME, this.update, this);
        egret3d.Input.addEventListener(egret3d.Event3D.RESIZE, this.onResize, this);

        document.onmousedown = (e) => { this.mouseDown(e); };
        document.onmousemove = (e) => { this.mouseMove(e); };
        document.onmouseup = (e) => { this.mouseUp(e); };

        document.ontouchstart = (e) => { this.touchStart(e) };
        document.ontouchmove = (e) => { this.touchMove(e) };
        document.ontouchend = (e) => { this.touchEnd(e) };
    }

    mousePress: boolean = false;
    lastPoint: CANNON.Vec3;
    direction: CANNON.Vec3;
    mouseDown(e: MouseEvent)
    {
        this.mousePress = true;
        this.lastPoint = new CANNON.Vec3(e.x, 0, -e.y);
    }

    mouseMove(e: MouseEvent)
    {
        if (this.mousePress)
        {
            var vec = new CANNON.Vec3(e.x, 0, -e.y);
            this.direction = vec.vsub(this.lastPoint);
            this.direction.normalize();
        }
    }

    mouseUp(e: MouseEvent)
    {
        this.mousePress = false;
    }

    touchStart(e: TouchEvent)
    {
        this.mousePress = true;
        this.lastPoint = new CANNON.Vec3(e.touches[0].clientX, 0, -e.touches[0].clientY);
    }
    
    touchMove(e: TouchEvent)
    {
        if (this.mousePress)
        {
            var vec = new CANNON.Vec3(e.touches[0].clientX, 0, -e.touches[0].clientY);
            this.direction = vec.vsub(this.lastPoint);
            this.direction.normalize();
        }
    }

    touchEnd(e: TouchEvent)
    {
        this.mousePress = false;
    }

    world: CANNON.World;
    physicsMaterial: CANNON.Material;
    sphereShape: CANNON.Sphere;
    sphereBody: CANNON.Body;
    sphereMesh: egret3d.Mesh;
    initCannon()
    {
        this.world = new CANNON.World();
        this.world.quatNormalizeSkip = 0;
        this.world.quatNormalizeFast = false;

        var solver = new CANNON.GSSolver();

        //这些参数不太懂
        this.world.defaultContactMaterial.contactEquationStiffness = 1e9;
        this.world.defaultContactMaterial.contactEquationRelaxation = 4;

        solver.iterations = 7;
        solver.tolerance = 0.1;
        var split = true;
        if (split)
        {
            this.world.solver = new CANNON.SplitSolver(solver);
        }
        else
        {
            this.world.solver = solver;
        }

        this.world.gravity.set(0, -9.8, 0);
        this.world.broadphase = new CANNON.NaiveBroadphase();

        // 创建物理材质
        this.physicsMaterial = new CANNON.Material("slipperyMaterial");
        var physicsContactMaterial = new CANNON.ContactMaterial(this.physicsMaterial, this.physicsMaterial);
        // 必须将物理材质加入world中
        this.world.addContactMaterial(physicsContactMaterial);

        // 创建sphere
        var radius = 1.5;
        this.sphereShape = new CANNON.Sphere(radius);
        this.sphereBody = new CANNON.Body({ mass: 10 });
        this.sphereBody.addShape(this.sphereShape);
        this.sphereBody.position.set(0, 5, 0);
        this.sphereBody.linearDamping = 0.9;
        this.world.addBody(this.sphereBody);

        // 创建plane
        var groundShape = new CANNON.Plane();
        var groundBody = new CANNON.Body({ mass: 0 });
        groundBody.addShape(groundShape);
        groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
        this.world.addBody(groundBody);
    }

    fps: number = 60;
    time: number = Date.now();
    update()
    {
        if (this.mousePress)
        {
            this.sphereBody.force.vadd(this.direction.mult(400), this.sphereBody.force);
        }

        //this._cameraCtrl.update();

        this.fps = 1000 / (Date.now() - this.time);
        this.time = Date.now();

        this.world.step(1 / this.fps);
        
        for (var i = 0; i < this.boxes.length; i++)
        {
            this.boxMeshes[i].position = new egret3d.Vector3D(this.boxes[i].position.x, this.boxes[i].position.y, this.boxes[i].position.z);
            this.boxMeshes[i].orientation = new egret3d.Quaternion(this.boxes[i].quaternion.x, this.boxes[i].quaternion.y, this.boxes[i].quaternion.z, this.boxes[i].quaternion.w);
        }
        
        this.sphereMesh.position = new egret3d.Vector3D(this.sphereBody.position.x, this.sphereBody.position.y, this.sphereBody.position.z);
    }

    onResize(e: egret3d.Event3D)
    {
        this._view3D.width = this._canvasEgret.width;
        this._view3D.height = this._canvasEgret.height;
    }
}

window.onload = () =>
{
    var a = new Basic();
    a.start();
};
